package org.com.system.util.sql;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.persistence.Table;

import org.com.system.util.mate.Link;
import org.com.system.util.mate.SQLMate;
import org.com.system.util.mate.Type;
import org.com.system.util.model.ActionValues;
import org.com.system.util.processor.StringValueProcessor;
import org.com.system.util.utils.CollectionUtils;
import org.com.system.util.utils.ModelUtils;
import org.com.system.util.utils.StrUtils;
import org.jboss.logging.Logger;
/**
 * 有关SQL方面的工具类
 * @author Gandilong
 *
 */
public class SQLUtils {

	public static int INSERT_OPERATOR=0;
	public static int UPDATE_OPERATOR=1;
	public static int SELECT_OPERATOR=2;
	public static int DELETE_OPERATOR=3;
	
	private static Logger logger=Logger.getLogger(SQLUtils.class);
	
	
	/**
	 * 通过实体类上的注解得到表名信息
	 * @param model 实体类
	 * @return String 字符串形式的表名
	 */
    public static String getTableName(Class<?> model){
    	String tableName=null;
    	if(model.isAnnotationPresent(Table.class)){
    		Table table=model.getAnnotation(Table.class);
    		tableName=table.name();
    	}
    	return tableName;
    }
	
	/**
	 * 通过实体类的Class对象得到相关实体类的字段名，并根据字段名计算出相关表的列名,规则是列名大写转小写，下划线去掉且下划线后面的字符大写。
	 * @param model 实体类
	 * @return 字符串形式的列名
	 */
	public static String[] getColumnNames(Class<?> model){
		Field[] fields=model.getDeclaredFields();
		String[] names=new String[fields.length];
		int i=0;
		for(Field field:fields){
			if(field.isAnnotationPresent(javax.persistence.Column.class)){
				names[i]=field.getAnnotation(javax.persistence.Column.class).name();
			}else{
				names[i]=addUnderline(field.getName());
			}
			i++;
		}
		return names;
	}
	
	/**
	 * 通过实体类的Class对象得到相关实体类的字段名，并处理为:field形做为参数。
	 * 如[columnA,columnB,columnC]-->[?,?,?],如果columnName=true，则返回[columnA,columnB,columnC]-->[columnA=?,columnB=?,columnC=?]
	 * haveId是否要保留ID列字段,true保留，false去掉
	 * @param model 实体类
	 * @return 字符串形式的列名
	 */
	public static String[] getColumnParams(Class<?> model,int operatorMode,boolean colon){
		String[] names=getColumnNames(model);
		String[] values=null;
		if(UPDATE_OPERATOR==operatorMode){
			names=CollectionUtils.cutValue(names, "id");
		}
		if(CollectionUtils.isNotEmpty(names)){
			final int mode=operatorMode;
			final boolean addColon=colon;
			final Class<?> modelClass=model;
			values=CollectionUtils.processValues(names, new StringValueProcessor() {
				@Override
				public String process(String column) {
					switch(mode){
					   case 0: 
						     if(addColon){
						    	 column=" :"+dropUnderline(column);
						     }else{
						    	 column=" ? ";
						     }
						     break;
					   case 1: 
						     column=getKeyName(column,modelClass,false,addColon);
						     break;
					   case 2: 
						     column=getKeyName(column,modelClass,true,addColon);
						     break;
					   case 3: 
						     column=getKeyName(column,modelClass,true,addColon);
						     break;
					   default : break;
					}
				    return column;
				}
			});
		}
		return values;
	}
	
	/**
	 * 值模式
	 * 得key1='key1_value' 或  key2='key2_value' 形式的字符串
	 * @param values 类型为ActionValues<String,Object>是需要的值
	 * @param model 实体类型
	 * @param queryMode 类型为 boolean ,true 表示自动模式匹配，false表示都用=匹配
	 * @return
	 */
    public static Object[] getColumnValues(ActionValues<String,Object> values,Class<?> model,boolean queryMode){
    	List<String> list=null;
    	Set<String> keys=null;
    	if(values.isNotEmpty()){
    		String key=null;
			keys=values.keySet();
			list=new ArrayList<String>();
			Iterator<String> it=keys.iterator();
			while(it.hasNext()){
                key=String.valueOf(it.next());
                if(ModelUtils.hasField(key, model)&&!values.isNull(key)){
    			    list.add(getKeyValue(key, values.getString(key), model, queryMode));
                }
			}
		}
		return list.toArray();
	}
	
	
	/**
	 * 得到实体中某个字段的键值对,在queryMode=true的情况下，会得到如下name like %aa%或 id=112
	 * 如果queryMode=false的情况，则会得到name='aa'
	 * @author Gandilong at 2012-9-6下午04:02:11
	 * @return 字符串形式的键值对。
	 */
	public static String getKeyValue(String key,String value,Class<?> model,boolean queryMode){
		String keyValue=null;
		if(StrUtils.isNotEmpty(key)&&StrUtils.isNotEmpty(value)){
			try{
			    if(model.getDeclaredField(key).isAnnotationPresent(SQLMate.class)&&queryMode){
			    	SQLMate mate=model.getDeclaredField(key).getAnnotation(SQLMate.class);
			    	keyValue=addUnderline(key)+" "+mate.link()+" "+processValue(mate.link(),mate.type(),value);
		 	    }else{
		 	    	keyValue=addUnderline(key)+" = '"+value+"' ";
		 	    }
			}catch(NoSuchFieldException e){
				logger.error("发生异常了！");
				e.printStackTrace();
			}
		}
		return keyValue;
	}
	
	/**
	 * 得到实体中某个字段的键值对,在queryMode=true的情况下，会得到如下name like %:aa%或 id=:id
	 * 如果queryMode=false的情况，则会得到name=':aa'或name='?'
	 * @author Gandilong at 2012-9-6下午04:02:11
	 * @return 字符串形式的键值对。
	 */
	public static String getKeyName(String key,Class<?> model,boolean queryMode,boolean colon){
		String keyValue=null;
		if(StrUtils.isNotEmpty(key)&&StrUtils.isNotEmpty(key)){
			try{
			    if(model.getDeclaredField(dropUnderline(key)).isAnnotationPresent(SQLMate.class)&&queryMode){
			    	SQLMate mate=model.getDeclaredField(dropUnderline(key)).getAnnotation(SQLMate.class);
			    	if(colon){
			    	    keyValue=key+" "+mate.link()+" "+processKey(mate.link(),mate.type(),dropUnderline(key));
			    	}else{
			    		keyValue=key+" "+mate.link()+" ? ";
			    	}
		 	    }else{
		 	    	if(colon){
		 	    		keyValue=key + "= :"+dropUnderline(key)+" ";
		 	    	}else{
		 	    	    keyValue=key + "= ? ";
		 	    	}
		 	    }
			}catch(NoSuchFieldException e){
				logger.error("发生异常了！");
				e.printStackTrace();
			}
		}
		return keyValue;
	}
	
	/**
	 * 去掉下划线,并转为小写
	 * @param tname
	 * @return
	 */
	public static String dropUnderline(String tname){
		
		tname=tname.toLowerCase();
		char[] tnames=tname.toCharArray();
		boolean _show=false;
		for(int i=0;i<tnames.length;i++){
			if("_".equals(String.valueOf(tnames[i]))){
				_show=true;
				continue;
			}
			if(_show){
				tnames[i]=Character.toUpperCase(tnames[i]);
				_show=false;
			}else{
				tnames[i]=tnames[i];
			}
		}
		return String.valueOf(tname);
	}
	
	/**
	 * 增加下划线,并转为大写
	 * @param tname
	 * @return
	 */
	public static String addUnderline(String tname){
		StringBuilder columnName=new StringBuilder();
		
		char[] tnames=tname.toCharArray();
		boolean _show=false;
		
		for(int i=0;i<tnames.length;i++){
			if(!Character.isLowerCase(tnames[i])){
				_show=true;
			}
			if(_show){
				columnName.append("_");
				columnName.append(String.valueOf(tnames[i]).toLowerCase());
				_show=false;
			}else{
				columnName.append(tnames[i]);
			}
		}
		return columnName.toString();
	}

	/**
	 * 根据不同的类型和连接符来设置匹配值key=:key
	 *@author Gandilong at 2012-9-6下午04:54:16 
	 */
	public static String processKey(Link link,Type type,String key){
		if(Type.STRING.equals(type)){
			if(Link.LIKE.equals(link)){
				key=" %:"+key+"% ";
			}else{
				key=" :"+key+" ";
			}
		}
		return key;
	}
	
	/**
	 * 根据不同的类型和连接符来设置匹配值,key='value'
	 *@author Gandilong at 2012-9-6下午04:54:16 
	 */
	public static String processValue(Link link,Type type,String value){
		if(type.equals(Type.STRING)){
			if(link.equals(Link.LIKE)){
				value=" '%"+value+"%' ";
			}else{
				value=" '"+value+"' ";
			}
		}
		return value;
	}
	
	public static void main(String[] args) {
		/*ActionValues<String,Object> values=new ActionValues<String,Object>();
		values.put("id", "aaa");
		values.put("userName", "uname");
		values.put("loginName", "lname");
		String a=StringUtils.join(SQLUtils.getColumnValues(values,User.class, false)," and ");*/
		System.out.println(addUnderline("abcJls"));
		
	}
	
}
